package com.iee.lock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写锁 和 ReentrantLock
 * 读写锁：
 *      读写锁的特点是：读读不互斥、读写互斥、写写互斥
 * ReentrantLock：
 *      不区分锁的读写，都是互斥
 *@ClassName ReentrantReadWriteLockDemo
 *@Description TODO
 *@Author longxiaonan@163.com
 *@Date 2022/5/7 0007 13:18
 */
public class ReentrantReadWriteLockDemo {
    public static void main(String[] args) {
//        readAndRead();
//        readAndWrite();
        WriteAndRead();
//        WriteAndWrite();
    }

    private static void WriteAndRead() {
        // 创建读写锁
        final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        // 创建写锁
        final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        // 创建读锁
        final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        // 使用写锁
        Thread t1 = new Thread(() -> {
            writeLock.lock();
            try {
                System.out.println("[t1]得到写锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t1]释放写锁.");
                writeLock.unlock();
            }
        });
        t1.start();
        // 使用读锁
        Thread t2 = new Thread(() -> {
            readLock.lock();
            try {
                System.out.println("[t2]得到读锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t2]释放读锁.");
                readLock.unlock();
            }
        });
        t2.start();
    }

    /**
     * 多个线程同时使用写锁也是互斥的，这称之为写写互斥
     */
    private static void WriteAndWrite() {
        // 创建读写锁
        final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        // 创建写锁
        final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        Thread t1 = new Thread(() -> {
            writeLock.lock();
            try {
                System.out.println("[t1]得到写锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t1]释放写锁.");
                writeLock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            writeLock.lock();
            try {
                System.out.println("[t2]得到写锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t2]释放写锁.");
                writeLock.unlock();
            }
        });
        t2.start();
    }

    /**
     * 读锁和写锁同时使用是互斥的（也就是不能同时获得），这称之为读写互斥
     */
    public static void readAndWrite() {
        // 创建读写锁
        final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        // 创建读锁
        final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        // 创建写锁
        final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
        // 使用读锁
        Thread t1 = new Thread(() -> {
            readLock.lock();
            try {
                System.out.println("[t1]得到读锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t1]释放读锁.");
                readLock.unlock();
            }
        });
        t1.start();
        // 使用写锁
        Thread t2 = new Thread(() -> {
            writeLock.lock();
            try {
                System.out.println("[t2]得到写锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t2]释放写锁.");
                writeLock.unlock();
            }
        });
        t2.start();
    }

    /**
     * 多个线程可以同时获取到读锁，称之为读读不互斥
     */
    public static void readAndRead() {
        // 创建读写锁
        final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        // 创建读锁
        final ReentrantReadWriteLock.ReadLock readLock = readWriteLock.readLock();
        Thread t1 = new Thread(() -> {
            readLock.lock();
            try {
                System.out.println("[t1]得到读锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t1]释放读锁.");
                readLock.unlock();
            }
        });
        t1.start();
        Thread t2 = new Thread(() -> {
            readLock.lock();
            try {
                System.out.println("[t2]得到读锁.");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("[t2]释放读锁.");
                readLock.unlock();
            }
        });
        t2.start();
    }
}
